<script setup lang="ts">
import { McBubble, McInput, McMarkdownCard } from '@matechat/core'
import { convertFileSrc } from '@tauri-apps/api/core'
import { Menu } from '@tauri-apps/api/menu'
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'
import { useDebounceFn, useEventListener } from '@vueuse/core'
import { onUnmounted, ref, watch, nextTick } from 'vue'

import { useDevice } from '@/composables/useDevice'
import { useModel } from '@/composables/useModel'
import { useSharedMenu } from '@/composables/useSharedMenu'
import { hideWindow, setAlwaysOnTop, showWindow } from '@/plugins/window'
import { useCatStore } from '@/stores/cat'
import { useModelStore } from '@/stores/model'
import { join } from '@/utils/path'
import OpenAI from 'openai';

const appWindow = getCurrentWebviewWindow()
const { pressedMouses, mousePosition, pressedLeftKeys, pressedRightKeys } = useDevice()
const { backgroundImage, handleDestroy, handleResize, handleMouseDown, handleMouseMove, handleKeyDown } = useModel()
const catStore = useCatStore()
const { getSharedMenu } = useSharedMenu()
const modelStore = useModelStore()
const resizing = ref(false)

onUnmounted(handleDestroy)

const debouncedResize = useDebounceFn(async () => {
  await handleResize()

  resizing.value = false
}, 100)

useEventListener('resize', () => {
  resizing.value = true

  debouncedResize()
})

watch(pressedMouses, handleMouseDown)

watch(mousePosition, handleMouseMove)

watch(pressedLeftKeys, (keys) => {
  handleKeyDown('left', keys.length > 0)
})

watch(pressedRightKeys, (keys) => {
  handleKeyDown('right', keys.length > 0)
})

watch(() => catStore.visible, async (value) => {
  value ? showWindow() : hideWindow()
})

watch(() => catStore.penetrable, (value) => {
  appWindow.setIgnoreCursorEvents(value)
}, { immediate: true })

watch(() => catStore.alwaysOnTop, setAlwaysOnTop, { immediate: true })

function handleWindowDrag() {
  appWindow.startDragging()
}

async function handleContextmenu(event: MouseEvent) {
  event.preventDefault()

  const menu = await Menu.new({
    items: await getSharedMenu(),
  })

  menu.popup()
}

function resolveImagePath(key: string, side: 'left' | 'right' = 'left') {
  return convertFileSrc(join(modelStore.currentModel!.path, 'resources', `${side}-keys`, `${key}.png`))
}

const client = ref<OpenAI>();

client.value = new OpenAI({
  apiKey: 'sk-qddptrhspowhfrpenazqpbemctraeivkhekmfyvastozlpml', // 模型APIKey
  baseURL: 'https://api.siliconflow.cn/v1', // 模型API地址
  dangerouslyAllowBrowser: true,
});

const messages = ref<any[]>([]);
const inputValue = ref('');
const startPage = ref(true);

const onSubmit = (evt: any) => {
  inputValue.value = '';
  startPage.value = false;
  messages.value = []
  // 用户发送消息
  messages.value.push({
    from: 'user',
    content: evt,
    avatarConfig: { name: 'user' },
  });

  fetchData(evt);
};

const renderContent = ref('')
const fetchData = async (ques: any) => {
  messages.value.push({
    from: 'model',
    content: '',
    avatarConfig: { name: 'model' },
    id: '',
    loading: true,
  });
  renderContent.value = '';
  const completion = await client.value!.chat.completions.create({
    model: 'Qwen/QwQ-32B', // 替换为自己的model名称
    messages: [{ role: 'user', content: ques }],
    stream: true, // 为 true 则开启接口的流式返回
  });
  for await (const chunk of completion) {
    if (messages.value[messages.value.length - 1].content) {
      messages.value[messages.value.length - 1].loading = false;
    }
    const content = chunk.choices[0]?.delta?.content || '';
    renderContent.value += content;
    const chatId = chunk.id;
    messages.value[messages.value.length - 1].content += content;
    messages.value[messages.value.length - 1].id = chatId;
  }
};

const inputExpanded = ref(false)
const inputRef = ref<HTMLInputElement>()
function expandInput() {
  if (!inputExpanded.value) {
    inputExpanded.value = true
    nextTick(() => {
      inputRef.value?.focus()
    })
  }
}
function collapseInput() {
  inputExpanded.value = false
}

const messageContainer = ref<HTMLElement | null>(null)
const bubbleEndFlag = ref<any>(null);

const typingEnd = async () => {
  let render = document.querySelector('.mc-markdown-render')
  bubbleEndFlag.value = render;
  await nextTick()
  if (bubbleEndFlag.value) {
    bubbleEndFlag.value.scrollTop = bubbleEndFlag.value.scrollHeight
  }
}


const typingOptions = {
  style: 'color',
  step: 2,
};

const showAskInput = ref(false)
</script>

<template>
  <div class="page">
    <div class="matechat-app">
      <McLayoutContent class="content-container">
        <template v-for="(msg, idx) in messages" :key="idx">

          <McBubble class="response-bubble" :class="{ 'loading-bubble': msg.loading }" v-if="msg.from === 'model'"
            :loading="msg.loading">
            <McMarkdownCard ref="messageContainer" :content="msg.content" @typing="typingEnd" :typing="true"
              :typingOptions="typingOptions">
            </McMarkdownCard>
            <span class="bubble-render-end"></span>
            <template #loadingTpl>
              <span class="loading-icon">
                <svg t="1751817534245" class="icon" viewBox="0 0 1024 1024" version="1.1"
                  xmlns="http://www.w3.org/2000/svg" p-id="7842" width="200" height="200">
                  <path
                    d="M469.333333 85.333333m42.666667 0l0 0q42.666667 0 42.666667 42.666667l0 128q0 42.666667-42.666667 42.666667l0 0q-42.666667 0-42.666667-42.666667l0-128q0-42.666667 42.666667-42.666667Z"
                    fill="#ffffff" opacity=".8" p-id="7843"></path>
                  <path
                    d="M469.333333 725.333333m42.666667 0l0 0q42.666667 0 42.666667 42.666667l0 128q0 42.666667-42.666667 42.666667l0 0q-42.666667 0-42.666667-42.666667l0-128q0-42.666667 42.666667-42.666667Z"
                    fill="#ffffff" opacity=".4" p-id="7844"></path>
                  <path
                    d="M938.666667 469.333333m0 42.666667l0 0q0 42.666667-42.666667 42.666667l-128 0q-42.666667 0-42.666667-42.666667l0 0q0-42.666667 42.666667-42.666667l128 0q42.666667 0 42.666667 42.666667Z"
                    fill="#ffffff" opacity=".2" p-id="7845"></path>
                  <path
                    d="M298.666667 469.333333m0 42.666667l0 0q0 42.666667-42.666667 42.666667l-128 0q-42.666667 0-42.666667-42.666667l0 0q0-42.666667 42.666667-42.666667l128 0q42.666667 0 42.666667 42.666667Z"
                    fill="#ffffff" opacity=".6" p-id="7846"></path>
                  <path
                    d="M783.530667 180.138667m30.169889 30.169889l0 0q30.169889 30.169889 0 60.339779l-90.509668 90.509668q-30.169889 30.169889-60.339779 0l0 0q-30.169889-30.169889 0-60.339779l90.509668-90.509668q30.169889-30.169889 60.339779 0Z"
                    fill="#ffffff" opacity=".1" p-id="7847"></path>
                  <path
                    d="M330.965333 632.661333m30.16989 30.16989l0 0q30.169889 30.169889 0 60.339778l-90.509668 90.509668q-30.169889 30.169889-60.339779 0l0 0q-30.169889-30.169889 0-60.339778l90.509668-90.509668q30.169889-30.169889 60.339779 0Z"
                    fill="#ffffff" opacity=".5" p-id="7848"></path>
                  <path
                    d="M843.861333 783.530667m-30.169889 30.169889l0 0q-30.169889 30.169889-60.339779 0l-90.509668-90.509668q-30.169889-30.169889 0-60.339779l0 0q30.169889-30.169889 60.339779 0l90.509668 90.509668q30.169889 30.169889 0 60.339779Z"
                    fill="#ffffff" opacity=".3" p-id="7849"></path>
                  <path
                    d="M391.338667 330.965333m-30.16989 30.16989l0 0q-30.169889 30.169889-60.339778 0l-90.509668-90.509668q-30.169889-30.169889 0-60.339779l0 0q30.169889-30.169889 60.339778 0l90.509668 90.509668q30.169889 30.169889 0 60.339779Z"
                    fill="#ffffff" opacity=".7" p-id="7850"></path>
                </svg>
              </span>
            </template>
            <template #bottom>
              <McBubble class="request-bubble" :variant="'none'" :content="messages[0].content">
                <span class="thinking-icon">
                  <svg t="1751744076573" class="icon" viewBox="0 0 1024 1024" version="1.1"
                    xmlns="http://www.w3.org/2000/svg" p-id="20712" width="200" height="200">
                    <path
                      d="M512 124.842667c164.992 0 298.666667 134.4 298.666667 300.032a300.074667 300.074667 0 0 1-127.701334 246.058666l-0.938666 88.789334a33.28 33.28 0 0 1-32.938667 33.28c-17.792 62.677333-73.088 106.154667-137.088 106.154666a139.477333 139.477333 0 0 1-135.04-104.533333c-20.266667-1.792-34.986667-16.64-34.986667-34.901333v-87.04C261.632 615.168 213.333333 524.074667 213.333333 424.874667c0-165.632 133.674667-300.032 298.666667-300.032z m61.312 668.16h-122.624l1.024 2.176-1.024-0.042667 2.645333 4.181333 2.901334 4.010667c12.501333 19.029333 33.237333 29.312 55.765333 29.312 26.325333 0 50.218667-14.08 63.146667-36.437333l-1.834667-3.242667z m40.106667-106.24H410.581333l-2.133333 37.546666 204.970667 2.176 2.133333-37.546666-2.133333-2.133334zM512 191.402667c-128.170667 0-232.192 104.490667-232.192 233.514666 0 79.488 39.765333 152.106667 104.490667 195.072l254.208 0.384a232.96 232.96 0 0 0 105.685333-195.413333c0-129.066667-104.021333-233.557333-232.192-233.557333z"
                      fill="#ccc" p-id="20713"></path>
                  </svg>
                </span>
                <span class="request-text">{{ messages[0].content }}</span>
              </McBubble>
            </template>
          </McBubble>
        </template>
      </McLayoutContent>

      <div class="ask-input" :class="{ expanded: inputExpanded, showAsk: showAskInput }" @click="expandInput"
        tabindex="0">
        <input v-show="inputExpanded" class="native-input" :value="inputValue" :maxlength="2000" placeholder=""
          @input="e => inputValue = (e.target as HTMLInputElement).value" @keydown.enter="onSubmit(inputValue)"
          ref="inputRef" @blur="collapseInput" />
        <span v-show="!inputExpanded" class="input-icon">
          <svg t="1751711666707" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
            p-id="4681" width="200" height="200">
            <path
              d="M512 64c259.2 0 469.333333 200.576 469.333333 448s-210.133333 448-469.333333 448a484.48 484.48 0 0 1-232.725333-58.88l-116.394667 50.645333a42.666667 42.666667 0 0 1-58.517333-49.002666l29.76-125.013334C76.629333 703.402667 42.666667 611.477333 42.666667 512 42.666667 264.576 252.8 64 512 64z"
              fill="#fff" stroke="#000" p-id="4682"></path>
            <path
              d="M512 64c259.2 0 469.333333 200.576 469.333333 448s-210.133333 448-469.333333 448a484.48 484.48 0 0 1-232.725333-58.88l-116.394667 50.645333a42.666667 42.666667 0 0 1-58.517333-49.002666l29.76-125.013334C76.629333 703.402667 42.666667 611.477333 42.666667 512 42.666667 264.576 252.8 64 512 64z m0 64C287.488 128 106.666667 300.586667 106.666667 512c0 79.573333 25.557333 155.434667 72.554666 219.285333l5.525334 7.317334 18.709333 24.192-26.965333 113.237333 105.984-46.08 27.477333 15.018667C370.858667 878.229333 439.978667 896 512 896c224.512 0 405.333333-172.586667 405.333333-384S736.512 128 512 128z m-157.696 341.333333a42.666667 42.666667 0 1 1 0 85.333334 42.666667 42.666667 0 0 1 0-85.333334z m159.018667 0a42.666667 42.666667 0 1 1 0 85.333334 42.666667 42.666667 0 0 1 0-85.333334z m158.997333 0a42.666667 42.666667 0 1 1 0 85.333334 42.666667 42.666667 0 0 1 0-85.333334z"
              fill="#000" stroke="#fff" p-id="4682" stroke-width="4"></path>

          </svg>
        </span>
      </div>
    </div>
    <div class="live2d-model relative size-screen overflow-hidden children:(absolute size-full)"
      :class="{ '-scale-x-100': catStore.mirrorMode }" :style="{ opacity: catStore.opacity / 100 }"
      @contextmenu="handleContextmenu" @mousedown="handleWindowDrag">
      <img :src="backgroundImage">

      <canvas id="live2dCanvas" />

      <img v-for="key in pressedLeftKeys" :key="key" :src="resolveImagePath(key)">

      <img v-for="key in pressedRightKeys" :key="key" :src="resolveImagePath(key, 'right')">

      <div v-show="resizing" class="flex items-center justify-center bg-black">
        <span class="text-center text-5xl text-white">
          重绘中...
        </span>
      </div>
    </div>
  </div>

</template>

<style scoped lang="scss">
.page {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: end;
  align-items: end;

  &:hover .ask-input {
    display: block;
  }
}

.live2d-model {
  height: calc(100vh - 100px);
  width: calc(100vw - 40px);
}

.matechat-app {
  display: flex;
  padding-bottom: 120px;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 999;
  pointer-events: none;

  .ask-input {
    display: none;
  }

  .content-container {
    display: flex;
    flex-direction: column-reverse;
  }

  .ask-input {
    position: absolute;
    right: 24px;
    bottom: 120px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    border-radius: 50%;
    transition: width 0.3s cubic-bezier(.4, 0, .2, 1), border-radius 0.3s cubic-bezier(.4, 0, .2, 1), background 0.3s;
    cursor: pointer;
    z-index: 9999;
    pointer-events: auto;

    .input-icon {
      width: 15vw;
      height: 15vw;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 50%;
      color: #888;
      user-select: none;
      pointer-events: none;
      font-size: 22px;
    }

    .native-input {
      display: none;
      width: 100%;
      height: 32px;
      padding: 8px 16px;
      background: transparent;
      border-radius: 16px;
      transition: background 0.2s;
      width: 100%;
      height: 20px;
      z-index: 9999;
      font-size: 12px;
      line-height: 1;
      border: none;
      outline: none;
    }
  }

  .ask-input.expanded {
    bottom: 6px;
    top: auto;
    left: calc(50% - 100px);
    width: 200px;
    height: 28px;
    border-radius: 24px;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 1));
    border-bottom: solid 1.2px #000;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: text;

    .input-icon {
      display: none;
    }

    .native-input {
      display: block;
      text-align: center;
    }
  }

  .request-bubble {
    color: #ccc;
    padding-left: 4px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transform: scale(0.8);
    transform-origin: left top;
    user-select: text;
    align-items: center;
    margin-top: 2px;

    .thinking-icon {
      display: inline-block;
      width: 20px;
      height: 20px;
      vertical-align: middle;
      margin-right: 2px;

      svg {
        width: 100%;
        height: 100%;
        transform: translateY(-2px);
      }
    }
  }

  .loading-bubble {
    padding-right: 15px;
    padding-bottom: 10px;

    &::after {
      display: none;
    }
  }

  .loading-icon {
    display: inline-block;
    width: 50px;
    height: 50px;

    svg {
      width: 100%;
      height: 100%;

      animation: loading .7s infinite steps(8);
    }
  }

  @keyframes loading {
    0% {
      transform: rotate(0deg);
    }

    100% {
      transform: rotate(360deg);
    }

  }

  .response-bubble {
    max-width: 60%;
    pointer-events: auto;
    transform: scale(0.9);
    transform-origin: left top;
    user-select: text;
    justify-content: end;

    &::after {
      content: '';
      position: absolute;
      right: 12px;
      bottom: 10px;
      width: 0;
      height: 0;
      border-width: 7px;
      border-style: solid;
      border-color: white transparent transparent transparent;
    }

    *::-webkit-scrollbar {
      opacity: 0;
    }

    :deep(.mc-bubble-content) {
      max-height: 90px;
      overflow: scroll;
      overflow-x: hidden;
      display: flex;
      // align-items: end;

      &::-webkit-scrollbar {
        width: 0px;
      }

      .mc-markdown-render::webkit-scrollbar {
        width: 0px;
      }

      .mc-markdown-render p {
        line-height: 22px;

      }
    }
  }
}
</style>
